home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / demo / medmfc.zip / MAGMAED.CPP < prev    next >
C/C++ Source or Header  |  1994-07-01  |  22KB  |  895 lines

  1. #include "stdafx.h"  // must be in mfc\src\stdafx.h
  2. #include "magmaed.hpp"
  3.  
  4.  
  5. ////////////////////////////////////////////////////////////////////
  6. // CMagmaEdit
  7. //
  8. // This code was taken from the CEdit section of mfc\src\winctrl.cpp
  9. //
  10. ////////////////////////////////////////////////////////////////////
  11. IMPLEMENT_DYNAMIC(CMagmaEdit, CEdit)
  12.  
  13. WNDPROC* CMagmaEdit::GetSuperWndProcAddr()
  14. {
  15.   static WNDPROC NEAR pfnSuper;
  16.   return &pfnSuper;
  17. }
  18.  
  19. BOOL CMagmaEdit::Create(DWORD dwStyle, const RECT& rect, 
  20.                         CWnd* pParentWnd, UINT nID)
  21. {
  22.   return CWnd::Create("MagmaEdit", NULL, dwStyle, rect, pParentWnd, nID);
  23. }
  24.  
  25. CMagmaEdit::~CMagmaEdit()
  26. {
  27.   DestroyWindow();
  28. }
  29.  
  30.  
  31. int CMagmaEdit::GetLastSearchPattern(LPSTR lpBuf)
  32. {
  33.   return (int) ::SendMessage(m_hWnd, ME_QUERYSEARCHSTRING, 0, (LONG) lpBuf);
  34. }
  35.  
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CMagmaEditView
  38.  
  39. IMPLEMENT_DYNCREATE(CMagmaEditView, CView)
  40.  
  41. #define new DEBUG_NEW
  42.  
  43. BEGIN_MESSAGE_MAP(CMagmaEditView, CView)
  44.   //{{AFX_MSG_MAP(CMagmaEditView)
  45.   ON_WM_CREATE()
  46.   ON_WM_PAINT()
  47.   ON_MESSAGE(WM_SETFONT, OnSetFont)
  48.   ON_EN_CHANGE(AFX_IDW_PANE_FIRST, OnEditChange)
  49.   ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateNeedSel)
  50.   ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateNeedClip)
  51.   ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateNeedText)
  52.   ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
  53.   ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  54.   ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  55.   ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  56.   ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  57.   ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
  58.   ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  59.   ON_UPDATE_COMMAND_UI(ID_EDIT_FIND, OnUpdateNeedText)
  60.   ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateNeedText)
  61.   ON_COMMAND(ID_EDIT_FIND, OnEditFind)
  62.   ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
  63.   ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateNeedFind)
  64.   ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
  65.   ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateNeedSel)
  66.   ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateNeedSel)
  67.  
  68.   ON_COMMAND(ID_EDIT_MARKLINE, OnEditMarkLine)
  69.   ON_COMMAND(ID_EDIT_MARKLINERANGE, OnEditMarkLineRange)
  70.   ON_COMMAND(ID_EDIT_STREAMMARK, OnEditMarkStream)
  71.   ON_COMMAND(ID_EDIT_RECTMARK, OnEditMarkRect)
  72.   ON_COMMAND(ID_EDIT_RESETMARK, OnEditMarkReset)
  73.  
  74.   //}}AFX_MSG_MAP
  75.  
  76. // Standard Print commands (print only - not preview)
  77. ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
  78. END_MESSAGE_MAP()
  79.  
  80. const DWORD CMagmaEditView::dwStyleDefault =
  81.     AFX_WS_DEFAULT_VIEW |
  82.     WS_HSCROLL | WS_VSCROLL |
  83.     ES_AUTOHSCROLL | ES_AUTOVSCROLL |
  84.     ES_MULTILINE | ES_NOHIDESEL;
  85.  
  86. // Operating system specific maximum buffer limit
  87. const DWORD CMagmaEditView::nMaxSize = 0x7FFFFFFFL;
  88.  
  89. // class name for control creation
  90. static char BASED_CODE szClassName[] = "MagmaEdit";
  91.  
  92. static HMODULE hMagmaEditModule = ::LoadLibrary("magmaed.dll");
  93. static HMODULE hBWCCModule = ::LoadLibrary("bwcc.dll");
  94.  
  95. /////////////////////////////////////////////////////////////////////////////
  96. // CMagmaEditView construction/destruction
  97.  
  98. CMagmaEditView::CMagmaEditView()
  99. {
  100.   ASSERT(hMagmaEditModule > (HMODULE) 32);
  101.   ASSERT(hBWCCModule > (HMODULE) 32);
  102.  
  103.   m_nTabStops = 8*4;  // default 8 character positions
  104.   m_hPrinterFont = NULL;
  105.   m_hMirrorFont = NULL;
  106. }
  107.  
  108. CMagmaEditView::~CMagmaEditView()
  109. {
  110.   ASSERT(m_hWnd == NULL);
  111. }
  112.  
  113. WNDPROC* CMagmaEditView::GetSuperWndProcAddr()
  114. {
  115.   static WNDPROC NEAR pfnSuper;
  116.   return &pfnSuper;
  117. }
  118.  
  119. BOOL CMagmaEditView::PreCreateWindow(CREATESTRUCT& cs)
  120. {
  121.   ASSERT(cs.lpszClass == NULL);
  122.   cs.lpszClass = szClassName;
  123.  
  124.   // map default CView style to default CMagmaEditView style
  125.   if (cs.style == AFX_WS_DEFAULT_VIEW)
  126.     cs.style = dwStyleDefault;
  127.  
  128.   return TRUE;
  129. }
  130.  
  131. int CMagmaEditView::OnCreate(LPCREATESTRUCT lpcs)
  132. {
  133.   if (CView::OnCreate(lpcs) != 0)
  134.     return -1;
  135.   //
  136.   // MODIFICATION : We should change LimitText so it takes a DWORD
  137.   //
  138.   GetEditCtrl().LimitText((UINT) nMaxSize);
  139.   GetEditCtrl().SetTabStops(m_nTabStops);
  140.   return 0;
  141. }
  142.  
  143. // EDIT controls always turn off WS_BORDER and draw it themselves
  144. #define CX_BORDER  1
  145. #define CY_BORDER  1
  146.  
  147. void CMagmaEditView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
  148. {
  149.   if (nAdjustType != 0)
  150.   {
  151.     // default behavior for in-place editing handles scrollbars
  152.     DWORD dwStyle = GetStyle();
  153.     if (dwStyle & WS_VSCROLL)
  154.       lpClientRect->right += ::GetSystemMetrics(SM_CXVSCROLL) - CX_BORDER;
  155.     if (dwStyle & WS_HSCROLL)
  156.       lpClientRect->bottom += ::GetSystemMetrics(SM_CYHSCROLL) - CY_BORDER;
  157.     return;
  158.   }
  159.  
  160.   ::AdjustWindowRect(lpClientRect, GetStyle() | WS_BORDER, FALSE);
  161. }
  162.  
  163. /////////////////////////////////////////////////////////////////////////////
  164. // CMagmaEditView document like functions
  165.  
  166. void CMagmaEditView::DeleteContents()
  167. {
  168.   ASSERT_VALID(this);
  169.   ASSERT(m_hWnd != NULL);
  170.   SetWindowText(NULL);
  171.   ASSERT_VALID(this);
  172. }
  173.  
  174. void CMagmaEditView::Serialize(CArchive& ar)
  175.   // Read and write CMagmaEditView object to archive, with length prefix.
  176. {
  177.   ASSERT_VALID(this);
  178.   ASSERT(m_hWnd != NULL);
  179.   if (ar.IsStoring())
  180.   {
  181.     DWORD nLen = GetBufferLength();
  182.     ar << nLen;
  183.     WriteToArchive(ar);
  184.   }
  185.   else
  186.   {
  187.     DWORD dwLen;
  188.     ar >> dwLen;
  189.     if (dwLen > nMaxSize)
  190.     {
  191.       AfxThrowArchiveException(CArchiveException::badIndex);
  192.       ASSERT(FALSE);
  193.     }
  194.     ReadFromArchive(ar, dwLen);
  195.   }
  196.   ASSERT_VALID(this);
  197. }
  198.  
  199. void CMagmaEditView::ReadFromArchive(CArchive& ar, DWORD nLen)
  200. // Read certain amount of text from the file, assume at least nLen
  201. // bytes are in the file.
  202. {
  203.   (void) nLen;
  204.  
  205.   ASSERT_VALID(this);
  206.  
  207.   ::SendMessage(GetEditCtrl().m_hWnd, ME_OPENFILE, ar.GetFile()->m_hFile, 0L);
  208.  
  209.   Invalidate();
  210.   ASSERT_VALID(this);
  211. }
  212.  
  213. void CMagmaEditView::WriteToArchive(CArchive& ar)
  214. // Write just the text to an archive, no length prefix.
  215. {
  216.   ASSERT_VALID(this);
  217.  
  218.   TRY
  219.   {
  220.     ::SendMessage(GetEditCtrl().m_hWnd, ME_WRITEFILE, ar.GetFile()->m_hFile, 0L);
  221.   }
  222.   CATCH_ALL(e)
  223.   {
  224.     THROW_LAST();
  225.     ASSERT(FALSE);
  226.   }
  227.   END_CATCH_ALL
  228.  
  229.   ASSERT_VALID(this);
  230. }
  231.  
  232. void CMagmaEditView::SerializeRaw(CArchive& ar)
  233. // Read/Write object as stand-alone file.
  234. {
  235.   ASSERT_VALID(this);
  236.   if (ar.IsStoring())
  237.   {
  238.     WriteToArchive(ar);
  239.   }
  240.   else  // reading from a file
  241.   {
  242.     CFile* pFile = ar.GetFile();
  243.     ASSERT(pFile->GetPosition() == 0);
  244.     DWORD nFileSize = pFile->GetLength();
  245.     // Make sure that the file isn't larger than what the buffer can hold
  246.     if (nFileSize > nMaxSize)
  247.     {
  248.       AfxMessageBox(AFX_IDP_FILE_TOO_LARGE);
  249.       AfxThrowUserException();
  250.       ASSERT(FALSE);
  251.     }
  252.     ReadFromArchive(ar, nFileSize);
  253.   }
  254.   ASSERT_VALID(this);
  255. }
  256.  
  257. /////////////////////////////////////////////////////////////////////////////
  258. // CMagmaEditView drawing
  259.  
  260. void CMagmaEditView::OnPaint()
  261. {
  262.   // do not call CView::OnPaint since it will call OnDraw
  263.   CWnd::OnPaint();
  264. }
  265.  
  266. void CMagmaEditView::OnDraw(CDC*)
  267. {
  268.   // do nothing here since CWnd::OnPaint() will repaint the EDIT control
  269. }
  270.  
  271. /////////////////////////////////////////////////////////////////////////////
  272. // CMagmaEditView commands
  273.  
  274. void CMagmaEditView::OnUpdateNeedSel(CCmdUI* pCmdUI)
  275. {
  276.   //
  277.   // Checks to see if there is any selected text in the buffer
  278.   //
  279.   // MODIFICATION : Add check for line marks
  280.   //
  281.   ASSERT_VALID(this);
  282.  
  283. #if 0
  284.   //
  285.   // Ifdef'ed out.. we should always be able to cut
  286.   //
  287.   int nStartChar, nEndChar;
  288.   GetEditCtrl().GetSel(nStartChar, nEndChar);
  289.   pCmdUI->Enable(nStartChar != nEndChar);
  290. #else
  291.   pCmdUI->Enable(TRUE);
  292. #endif
  293.  
  294.   ASSERT_VALID(this);
  295. }
  296.  
  297.  
  298. void CMagmaEditView::OnUpdateNeedClip(CCmdUI* pCmdUI)
  299. {
  300.   //
  301.   // Checks to see if there is text waiting in the clipboard. If so,
  302.   // the Paste menu item is enabled.
  303.   //
  304.   ASSERT_VALID(this);
  305.   pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
  306.   ASSERT_VALID(this);
  307. }
  308.  
  309.  
  310. void CMagmaEditView::OnUpdateNeedText(CCmdUI* pCmdUI)
  311. {
  312.   ASSERT_VALID(this);
  313.   pCmdUI->Enable(GetBufferLength() != 0);
  314.   ASSERT_VALID(this);
  315. }
  316.  
  317.  
  318. void CMagmaEditView::OnUpdateEditUndo(CCmdUI* pCmdUI)
  319. {
  320.   ASSERT_VALID(this);
  321.   //
  322.   // Checks to see if anything is in the UNDO stack
  323.   //
  324.   pCmdUI->Enable(GetEditCtrl().CanUndo());
  325.   ASSERT_VALID(this);
  326. }
  327.  
  328.  
  329. void CMagmaEditView::OnEditChange()
  330. {
  331.   ASSERT_VALID(this);
  332.   GetDocument()->SetModifiedFlag();
  333.   ASSERT_VALID(this);
  334. }
  335.  
  336.  
  337. void CMagmaEditView::OnEditCut()
  338. {
  339.   ASSERT_VALID(this);
  340.   GetEditCtrl().Cut();
  341.   ASSERT_VALID(this);
  342. }
  343.  
  344.  
  345. void CMagmaEditView::OnEditCopy()
  346. {
  347.   ASSERT_VALID(this);
  348.   GetEditCtrl().Copy();
  349.   ASSERT_VALID(this);
  350. }
  351.  
  352.  
  353. void CMagmaEditView::OnEditPaste()
  354. {
  355.   ASSERT_VALID(this);
  356.   GetEditCtrl().Paste();
  357.   ASSERT_VALID(this);
  358. }
  359.  
  360.  
  361. void CMagmaEditView::OnEditClear()
  362. {
  363.   ASSERT_VALID(this);
  364.   GetEditCtrl().Clear();
  365.   ASSERT_VALID(this);
  366. }
  367.  
  368.  
  369. void CMagmaEditView::OnEditUndo()
  370. {
  371.   ASSERT_VALID(this);
  372.   GetEditCtrl().Undo();
  373.   ASSERT_VALID(this);
  374. }
  375.  
  376.  
  377. void CMagmaEditView::OnEditSelectAll()
  378. {
  379.   ASSERT_VALID(this);
  380.   //
  381.   // Select everything in the buffer
  382.   //
  383.   GetEditCtrl().SetSel(0, -1);
  384.   ASSERT_VALID(this);
  385. }
  386.  
  387.  
  388. void CMagmaEditView::OnEditMarkLine()
  389. {
  390.   ASSERT_VALID(this);
  391.   ::SendMessage(GetEditCtrl().m_hWnd, ME_MARKLINE, 0, 0L);
  392.   ASSERT_VALID(this);
  393. }
  394. void CMagmaEditView::OnEditMarkLineRange()
  395. {
  396.   ASSERT_VALID(this);
  397.   ::SendMessage(GetEditCtrl().m_hWnd, ME_MARKLINERANGE, 0, 0L);
  398.   ASSERT_VALID(this);
  399. }
  400. void CMagmaEditView::OnEditMarkStream()
  401. {
  402.   ASSERT_VALID(this);
  403.   ::SendMessage(GetEditCtrl().m_hWnd, ME_STREAMMARK, 0, 0L);
  404.   ASSERT_VALID(this);
  405. }
  406. void CMagmaEditView::OnEditMarkRect()
  407. {
  408.   ASSERT_VALID(this);
  409.   ::SendMessage(GetEditCtrl().m_hWnd, ME_RECTMARK, 0, 0L);
  410.   ASSERT_VALID(this);
  411. }
  412. void CMagmaEditView::OnEditMarkReset()
  413. {
  414.   ASSERT_VALID(this);
  415.   ::SendMessage(GetEditCtrl().m_hWnd, ME_RESETMARK, 0, 0L);
  416.   ASSERT_VALID(this);
  417. }
  418.  
  419.  
  420. /////////////////////////////////////////////////////////////////////////////
  421. // CMagmaEditView Font Handling
  422.  
  423. LRESULT CMagmaEditView::OnSetFont(WPARAM wParam, LPARAM lParam)
  424. {
  425.   ASSERT_VALID(this);
  426.   Default();
  427.  
  428.   //
  429.   //
  430.   //
  431. //  GetEditCtrl().SetFont(wParam);
  432.  
  433.   GetEditCtrl().SetTabStops(m_nTabStops);
  434.   ASSERT_VALID(this);
  435.   return 0;
  436. }
  437.  
  438.  
  439. void CMagmaEditView::SetPrinterFont(CFont* pFont)
  440. {
  441.   ASSERT_VALID(this);
  442.   m_hPrinterFont = (HFONT)pFont->GetSafeHandle();
  443.   ASSERT_VALID(this);
  444. }
  445.  
  446. CFont* CMagmaEditView::GetPrinterFont() const
  447. {
  448.   ASSERT_VALID(this);
  449.   return CFont::FromHandle(m_hPrinterFont);
  450. }
  451.  
  452. /////////////////////////////////////////////////////////////////////////////
  453. // CMagmaEditView attributes
  454.  
  455. DWORD CMagmaEditView::GetBufferLength() const
  456. {
  457.   ASSERT_VALID(this);
  458.   ASSERT(m_hWnd != NULL);
  459.   DWORD nLen = GetWindowTextLength();
  460.   return nLen;
  461. }
  462.  
  463. /////////////////////////////////////////////////////////////////////////////
  464. // CMagmaEditView Find & Replace
  465.  
  466. void CMagmaEditView::OnUpdateNeedFind(CCmdUI* pCmdUI)
  467. {
  468.   ASSERT_VALID(this);
  469.  
  470.   //
  471.   // Checks to see if there is a previous search pattern
  472.   //
  473.   // MODIFICATION : Use a MagmaEdit message to query the previous
  474.   //                search string
  475.   //                     GetEditCtrl().GetLastSearchPattern() > 0
  476.   //
  477.   //
  478.   pCmdUI->Enable(GetBufferLength() != 0 &&
  479.                  GetEditCtrl().GetLastSearchPattern() > 0);
  480.  
  481.   ASSERT_VALID(this);
  482. }
  483.  
  484.  
  485. void CMagmaEditView::OnEditFind()
  486. {
  487.   ASSERT_VALID(this);
  488.   OnEditFindReplace(TRUE);
  489.   ASSERT_VALID(this);
  490. }
  491.  
  492. void CMagmaEditView::OnEditReplace()
  493. {
  494.   ASSERT_VALID(this);
  495.   OnEditFindReplace(FALSE);
  496.   ASSERT_VALID(this);
  497. }
  498.  
  499. void CMagmaEditView::OnEditRepeat()
  500. {
  501.   ASSERT_VALID(this);
  502.   if (::SendMessage(GetEditCtrl().m_hWnd, ME_SEARCHAGAIN, 0, 0L) == 0)
  503.     OnTextNotFound();
  504. }
  505.  
  506. void CMagmaEditView::OnEditFindReplace(BOOL bFindOnly)
  507. {
  508.   ASSERT_VALID(this);
  509.   if (::SendMessage(GetEditCtrl().m_hWnd,
  510.                     (bFindOnly) ? ME_FSEARCH : ME_FREPLACE,
  511.                     0,
  512.                     0L) == 0)
  513.     OnTextNotFound();
  514. }
  515.  
  516. void CMagmaEditView::OnFindNext(LPCSTR lpszFind, BOOL bNext, BOOL bCase)
  517. {
  518.   ASSERT_VALID(this);
  519. }
  520.  
  521. void CMagmaEditView::OnReplaceSel(LPCSTR lpszFind, BOOL bNext, BOOL bCase,
  522.                                   LPCSTR lpszReplace)
  523. {
  524.   ASSERT_VALID(this);
  525. }
  526.  
  527. void CMagmaEditView::OnReplaceAll(LPCSTR lpszFind, LPCSTR lpszReplace, 
  528.                                   BOOL bCase)
  529. {
  530.   ASSERT_VALID(this);
  531. }
  532.  
  533. LRESULT CMagmaEditView::OnFindReplaceCmd(WPARAM, LPARAM lParam)
  534. {
  535.   ASSERT_VALID(this);
  536.   return 0;
  537. }
  538.  
  539. void CMagmaEditView::OnTextNotFound(LPCSTR)
  540. {
  541.   ASSERT_VALID(this);
  542.   MessageBeep(0);
  543. }
  544.  
  545.  
  546. /////////////////////////////////////////////////////////////////////////////
  547. // CMagmaEditView Tab Stops
  548.  
  549. void CMagmaEditView::SetTabStops(int nTabStops)
  550. {
  551.   ASSERT_VALID(this);
  552.   m_nTabStops = nTabStops;
  553.   GetEditCtrl().SetTabStops(m_nTabStops);
  554.   Invalidate();
  555.   ASSERT_VALID(this);
  556. }
  557.  
  558. /////////////////////////////////////////////////////////////////////////////
  559. // CMagmaEditView diagnostics
  560.  
  561. #ifdef _DEBUG
  562. void CMagmaEditView::AssertValid() const
  563. {
  564.   CView::AssertValid();
  565.   ASSERT_VALID(&m_aPageStart);
  566.  
  567.   if (m_hPrinterFont != NULL)
  568.     ASSERT_VALID(CFont::FromHandle(m_hPrinterFont));
  569.  
  570.   if (m_hMirrorFont != NULL)
  571.     ASSERT_VALID(CFont::FromHandle(m_hMirrorFont));
  572. }
  573.  
  574. void CMagmaEditView::Dump(CDumpContext& dc) const
  575. {
  576.   CView::Dump(dc);
  577.   AFX_DUMP1(dc, "\nm_nTabStops = ", m_nTabStops);
  578.   if (m_hPrinterFont != NULL)
  579.     AFX_DUMP1(dc, "\nm_hPrinterFont ", (UINT)m_hPrinterFont);
  580.   if (m_hMirrorFont != NULL)
  581.     AFX_DUMP1(dc, "\nm_hMirrorFont ", (UINT)m_hMirrorFont);
  582.   AFX_DUMP1(dc, "\nm_aPageStart ", &m_aPageStart);
  583. }
  584. #endif //_DEBUG
  585.  
  586. /////////////////////////////////////////////////////////////////////////////
  587.  
  588. static UINT NEAR PASCAL
  589. ClipLine(CDC* pDC, int aCharWidths[256], int cxLine, int nTabStop, 
  590.          LPCSTR lpszText, UINT nChars)
  591. {
  592.   ASSERT_VALID(pDC);
  593.  
  594.   TEXTMETRIC tm;
  595.   pDC->GetTextMetrics(&tm);
  596.  
  597.   // make an initial guess on the number of characters that will fit
  598.   int cx = 0;
  599.   LPCSTR lpszStart = lpszText;
  600.   LPCSTR lpszStop = lpszText + nChars;
  601.   LPCSTR lpsz = lpszStart;
  602.   while (lpsz < lpszStop)
  603.   {
  604.     if (*lpsz == '\t')
  605.       cx += nTabStop - (cx % nTabStop);
  606.     else
  607.     {
  608. #ifdef AFXDATA_DEFINED
  609.       if (afxData.bDBCS && _AfxIsDBCSLeadByte(*lpsz))
  610.       {
  611.         ++lpsz;
  612.         cx += tm.tmAveCharWidth;
  613.       }
  614.       else
  615. #endif
  616.         cx += aCharWidths[(BYTE)*lpsz];
  617.     }
  618.     ++lpsz;
  619.     if (cx > cxLine)
  620.       break;
  621.   }
  622.  
  623.   // adjust for errors in the guess
  624.   cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  625.   if (cx > cxLine)
  626.   {
  627.     // remove characters until it fits
  628.     do
  629.     {
  630.       ASSERT(lpsz != lpszStart);
  631. #ifdef AFXDATA_DEFINED
  632.       if (afxData.bDBCS)
  633.         lpsz = AnsiPrev(lpszStart, lpsz);
  634.       else
  635. #endif
  636.         --lpsz;
  637.       cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  638.     } while (cx > cxLine);
  639.   }
  640.   else if (cx < cxLine)
  641.   {
  642.     // add characters until it doesn't fit
  643.     while (lpsz < lpszStop)
  644.     {
  645.       lpsz = AnsiNext(lpsz);
  646.       ASSERT(lpsz <= lpszStop);
  647.       cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  648.       if (cx > cxLine)
  649.       {
  650. #ifdef AFXDATA_DEFINED
  651.         if (afxData.bDBCS)
  652.           lpsz = AnsiPrev(lpszStart, lpsz);
  653.         else
  654. #endif
  655.           --lpsz;
  656.         break;
  657.       }
  658.     }
  659.   }
  660.  
  661.   // return index of character just past the last that would fit
  662.   return lpsz - lpszText;
  663. }
  664.  
  665.  
  666. UINT   // returns the line # which starts the next page
  667. CMagmaEditView::PrintInsideRect(CDC* pDC, RECT& rectLayout,
  668.   UINT nLineStart,  // this is the 0-based starting line
  669.   UINT nLineStop)   // this is the 0-based ending line
  670.   // worker function for laying out text in a rectangle.
  671. {
  672.   ASSERT_VALID(this);
  673.   ASSERT_VALID(pDC);
  674.  
  675.   // get buffer and real starting and ending postions
  676.   UINT nLines = GetEditCtrl().GetLineCount();
  677.   if (nLineStart >= nLines)
  678.     return nLines;
  679.  
  680.   LPSTR lpszText = new char[2048];
  681.  
  682.   if (nLineStop > nLines)
  683.     nLineStop = nLines;
  684.   ASSERT(nLineStart < nLines);
  685.  
  686.   // calculate text & tab metrics
  687.   TEXTMETRIC tm;
  688.   pDC->GetTextMetrics(&tm);
  689.   int cyChar = tm.tmHeight;
  690.   int nTabStop = m_nTabStops*pDC->GetTabbedTextExtent("\t",1,0,NULL).cx / 8 / 4;
  691.   int aCharWidths[256];
  692.   pDC->GetCharWidth(0, 255, aCharWidths);
  693.  
  694.   int y = rectLayout.top;
  695.   UINT cx = rectLayout.right - rectLayout.left;
  696.  
  697.   VERIFY(pDC->SaveDC() != 0);
  698.   BOOL bLayoutOnly = pDC->IntersectClipRect(&rectLayout) == NULLREGION;
  699.  
  700.   do
  701.   {
  702.     // Get the current line into lpszBuffer
  703.     GetEditCtrl().GetLine(nLineStart, lpszText, 2048);
  704.     UINT nChars = lstrlen(lpszText);
  705.  
  706.     if (nChars == 0)
  707.     {
  708.       y += cyChar;
  709.     }
  710.     else
  711.     {
  712.       // non-word wrap printing (much easier and faster)
  713.       CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
  714.       if (!bLayoutOnly && pDC->RectVisible(rect))
  715.       {
  716.         UINT nIndexClip = ClipLine(pDC, aCharWidths, cx, nTabStop,
  717.           lpszText, nChars);
  718.         if (nIndexClip < nChars)
  719.         {
  720. #ifdef AFXDATA_DEFINED
  721.           if (_AfxIsDBCSLeadByte(*(lpszText+nIndexClip)))
  722.             nIndexClip++;
  723. #endif
  724.           nIndexClip++;
  725.         }
  726.         pDC->TabbedTextOut(rect.left, y,
  727.           (LPCSTR)lpszText, nIndexClip, 1,
  728.           &nTabStop, rect.left);
  729.       }
  730.       y += cyChar;
  731.     }
  732.     nLineStart++;
  733.   }
  734.   while (nLineStart < nLineStop && y+cyChar <= rectLayout.bottom);
  735.  
  736.   VERIFY(pDC->RestoreDC(-1));
  737.   ASSERT_VALID(this);
  738.  
  739.   rectLayout.bottom = y;
  740.   return nLineStart;
  741. }
  742.  
  743.  
  744. /////////////////////////////////////////////////////////////////////////////
  745. // CMagmaEditView Printing support
  746.  
  747. BOOL CMagmaEditView::OnPreparePrinting(CPrintInfo* pInfo)
  748. {
  749.   return DoPreparePrinting(pInfo);
  750. }
  751.  
  752. void CMagmaEditView::OnBeginPrinting(CDC* pDC, CPrintInfo*)
  753. {
  754.   ASSERT_VALID(this);
  755.   ASSERT_VALID(pDC);
  756.   // initialize page start vector
  757.   ASSERT(m_aPageStart.GetSize() == 0);
  758.   m_aPageStart.Add(0);
  759.   ASSERT(m_aPageStart.GetSize() > 0);
  760.  
  761.   if (m_hPrinterFont == NULL)
  762.   {
  763.     // get current screen font object metrics
  764.     CFont* pFont = GetFont();
  765.     LOGFONT lf;
  766.     if (pFont == NULL)
  767.       return;
  768.     pFont->GetObject(sizeof(LOGFONT), &lf);
  769.     static char BASED_CODE szSystem[] = "system";
  770.     if (lstrcmpi((LPCSTR)lf.lfFaceName, szSystem) == 0)
  771.       return;
  772.  
  773.     // map to printer font metrics
  774.     HDC hDCFrom = ::GetDC(NULL);
  775.     lf.lfHeight = ::MulDiv(lf.lfHeight, pDC->GetDeviceCaps(LOGPIXELSY),
  776.       ::GetDeviceCaps(hDCFrom, LOGPIXELSY));
  777.     lf.lfWidth = ::MulDiv(lf.lfWidth, pDC->GetDeviceCaps(LOGPIXELSX),
  778.       ::GetDeviceCaps(hDCFrom, LOGPIXELSX));
  779.     ::ReleaseDC(NULL, hDCFrom);
  780.  
  781.     //
  782.     // MagmaEd uses an OEM_CHARSET screen font. However, for our
  783.     // HP LaserJet, Windows maps this font into a SCRIPT printer font.
  784.     // So, in order to get a normal font, we must set the lfCharSet to 
  785.     // DEFAULT_CHARSET.
  786.     //
  787.     lf.lfCharSet = DEFAULT_CHARSET;
  788.  
  789.     // create it, if it fails we just the the printer's default.
  790.     m_hMirrorFont = ::CreateFontIndirect(&lf);
  791.     m_hPrinterFont = m_hMirrorFont;
  792.   }
  793.   ASSERT_VALID(this);
  794. }
  795.  
  796. BOOL CMagmaEditView::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
  797.   // attempts pagination to pInfo->m_nCurPage, TRUE == success
  798. {
  799.   ASSERT_VALID(this);
  800.   ASSERT_VALID(pDC);
  801.  
  802.   CRect rectSave = pInfo->m_rectDraw;
  803.   UINT nPageSave = pInfo->m_nCurPage;
  804.   ASSERT(nPageSave > 1);
  805.   ASSERT(nPageSave >= (UINT)m_aPageStart.GetSize());
  806.   VERIFY(pDC->SaveDC() != 0);
  807.   pDC->IntersectClipRect(0, 0, 0, 0);
  808.   pInfo->m_nCurPage = m_aPageStart.GetSize();
  809.   while (pInfo->m_nCurPage < nPageSave)
  810.   {
  811.     ASSERT(pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize());
  812.     OnPrepareDC(pDC, pInfo);
  813.     ASSERT(pInfo->m_bContinuePrinting);
  814.     pInfo->m_rectDraw.SetRect(0, 0,
  815.       pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  816.     pDC->DPtoLP(&pInfo->m_rectDraw);
  817.     OnPrint(pDC, pInfo);
  818.     if (pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize())
  819.       break;
  820.     ++pInfo->m_nCurPage;
  821.   }
  822.   BOOL bResult = pInfo->m_nCurPage == nPageSave;
  823.   VERIFY(pDC->RestoreDC(-1));
  824.   pInfo->m_nCurPage = nPageSave;
  825.   pInfo->m_rectDraw = rectSave;
  826.   ASSERT_VALID(this);
  827.   return bResult;
  828. }
  829.  
  830. void CMagmaEditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  831. {
  832.   ASSERT_VALID(this);
  833.   ASSERT_VALID(pDC);
  834.   ASSERT(pInfo != NULL);  // overriding OnPaint -- never get this.
  835.  
  836.   if (pInfo->m_nCurPage > (UINT)m_aPageStart.GetSize() &&
  837.     !PaginateTo(pDC, pInfo))
  838.   {
  839.     // can't paginate to that page, thus cannot print it.
  840.     pInfo->m_bContinuePrinting = FALSE;
  841.   }
  842.   ASSERT_VALID(this);
  843. }
  844.  
  845. void CMagmaEditView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
  846. {
  847.   ASSERT_VALID(this);
  848.   ASSERT_VALID(pDC);
  849.   ASSERT(pInfo != NULL);
  850.   ASSERT(pInfo->m_bContinuePrinting);
  851.  
  852.   CFont* pOldFont = NULL;
  853.   if (m_hPrinterFont != NULL)
  854.     pOldFont = pDC->SelectObject(CFont::FromHandle(m_hPrinterFont));
  855.   pDC->SetBkMode(TRANSPARENT);
  856.  
  857.   UINT nPage = pInfo->m_nCurPage;
  858.   ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
  859.   UINT nIndex = m_aPageStart[nPage-1];
  860.  
  861.   // print as much as possible in the current page.
  862.   nIndex = PrintInsideRect(pDC, pInfo->m_rectDraw, nIndex, 0xFFFF);
  863.  
  864.   if (pOldFont != NULL)
  865.     pDC->SelectObject(pOldFont);
  866.  
  867.   // update pagination information for page just printed
  868.   if (nPage == (UINT)m_aPageStart.GetSize())
  869.   {
  870.     if (nIndex < (UINT) GetEditCtrl().GetLineCount())
  871.       m_aPageStart.Add(nIndex);
  872.   }
  873.   else
  874.   {
  875.     ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
  876.     ASSERT(nIndex == m_aPageStart[nPage+1-1]);
  877.   }
  878. }
  879.  
  880. void CMagmaEditView::OnEndPrinting(CDC*, CPrintInfo*)
  881. {
  882.   ASSERT_VALID(this);
  883.  
  884.   m_aPageStart.RemoveAll();
  885.   if (m_hMirrorFont != NULL && m_hPrinterFont == m_hMirrorFont)
  886.   {
  887.     ::DeleteObject(m_hMirrorFont);
  888.     m_hMirrorFont = NULL;
  889.     m_hPrinterFont = NULL;
  890.   }
  891. }
  892.  
  893.  
  894.  
  895.